home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: UniversalModule.c Contains: HID Module for USB Universal Version: xxx put version here xxx Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. */ #include <Types.h> #include <Devices.h> #include <processes.h> #include <DriverServices.h> #include <USB.h> #include "UniversalModule.h" usbUniversalPBStruct myUniversalPB; void SetParamBlock(USBInterfaceRef theInterfaceRef, USBPB * paramblock); Boolean immediateError(OSStatus err); void SetParamBlock(USBInterfaceRef theInterfaceRef, USBPB * paramblock) { paramblock->pbVersion = kUSBCurrentPBVersion; paramblock->pbLength = sizeof(usbUniversalPBStruct); paramblock->usbReference = theInterfaceRef; paramblock->usbWValue = 0; paramblock->usbWIndex = 0; paramblock->usbBuffer = nil; paramblock->usbReqCount = 0; paramblock->usbClassType = 0; paramblock->usbSubclass = 0; paramblock->usbFlags = 0; paramblock->usbOther = 0; paramblock->usbStatus = noErr; paramblock->usbCompletion = (USBCompletion) TransactionCompletionProc; } Boolean immediateError(OSStatus err) { return((err != kUSBPending) && (err != noErr) ); } void UniversalModuleInitiateTransaction(USBPB *pb) { register usbUniversalPBStruct *pUniversalPB; OSStatus myErr; UInt32 size; UInt32 count; USBHIDReportDesc * currentDesc; usbHIDDescriptorInfo * currentOwnedDesc; pUniversalPB = (usbUniversalPBStruct *)(pb); pUniversalPB->transDepth++; if (pUniversalPB->transDepth < 0) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: transDepth < 0 (initiation)", pUniversalPB->transDepth ); } if (pUniversalPB->transDepth > 1) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: transDepth > 1 (initiation)", pUniversalPB->transDepth ); } switch(pUniversalPB->pb.usbRefcon & ~kRetryTransaction) { case kGetHIDDesc: pUniversalPB->pb.usbWIndex = 0; pUniversalPB->pb.usbBuffer = &pUniversalPB->hidDiscriptor; pUniversalPB->pb.usbReqCount = sizeof (pUniversalPB->hidDiscriptor); pUniversalPB->pb.usbOther = kUSBHIDDesc; pUniversalPB->pb.usbRefcon |= kCompletionPending; myErr = USBFindNextAssociatedDescriptor(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: kGetHIDDesc (ImmediateError)", myErr); } break; case kAllocHIDOwnedDescMem: // we will allocate 1 block to hold all the hid descriptor stuff: // first an array of 'usbHIDDescriptorInfo' containing type, length, and ptrs to the data later in the block // then the actual descriptors, which will be pointed by the usbHIDDescriptorInfo array count = pUniversalPB->hidDiscriptor.d.hidNumDescriptors; size = count * sizeof (usbHIDDescriptorInfo); // inital part for the array // now add for each descriptor currentDesc = (USBHIDReportDesc *) &pUniversalPB->hidDiscriptor.d.hidDescriptorType; while (count--) { size += (currentDesc->hidDescriptorLengthHi << 8) + currentDesc->hidDescriptorLengthLo; ; currentDesc = (USBHIDReportDesc *) (((UInt8 *) currentDesc) + 3); // make _sure_ we add 3 bytes not 4 regardless of struct alignment } // now ask usbserviceslib to allocate the memory pUniversalPB->pb.usbReqCount = pUniversalPB->allocatedBufferSize = size; pUniversalPB->pb.usbFlags = 0; pUniversalPB->pb.usbRefcon |= kCompletionPending; myErr = USBAllocMem(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: kAllocHIDOwnedDescMem (ImmediateError)", myErr); } break; case kGet1OwnedHIDDesc: // hidOwnedDescriptorsCount is the number of owned decriptors we have successfully fetched currentOwnedDesc = &pUniversalPB->hidOwnedDiscriptors[pUniversalPB->hidOwnedDescriptorsCount]; SetParamBlock(pUniversalPB->interfaceRef, &pUniversalPB->pb); pUniversalPB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface); // 10000001 pUniversalPB->pb.usbBRequest = kUSBRqGetDescriptor; pUniversalPB->pb.usbWValue = (currentOwnedDesc->type << 8) + currentOwnedDesc->typeIndex; // type and index pUniversalPB->pb.usbWIndex = pUniversalPB->interfaceNum; // interface number pUniversalPB->pb.usbReqCount = currentOwnedDesc->length; pUniversalPB->pb.usbBuffer = currentOwnedDesc->descriptor; pUniversalPB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: kGet1OwnedHIDDesc (ImmediateError)", myErr); } break; case kConfigureInterface: SetParamBlock(pUniversalPB->interfaceRef, &pUniversalPB->pb); pUniversalPB->pb.usbRefcon |= kCompletionPending; pUniversalPB->pb.usbBuffer = 0; pUniversalPB->pb.usbReqCount = 0; pUniversalPB->pb.usbActCount = 0; myErr = USBConfigureInterface(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: kConfigureInterface (ImmediateError)", myErr); } break; case kFindInterruptPipe: pUniversalPB->pb.usbFlags = kUSBIn; pUniversalPB->pb.usbClassType = kUSBInterrupt; // pUniversalPB->pb.usbReference is interface ref, returns as pipe ref pUniversalPB->pb.usbRefcon |= kCompletionPending; myErr = USBFindNextPipe(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: kFindInterruptPipe (ImmediateError)", myErr); } break; case kReadInterruptPipe: pUniversalPB->pb.usbBuffer = (Ptr) pUniversalPB->hidReport; pUniversalPB->pb.usbReqCount = pUniversalPB->maxPacketSize; pUniversalPB->pb.usbWIndex = pUniversalPB->interfaceNum; pUniversalPB->pb.usbFlags = 0; pUniversalPB->pb.usbRefcon |= kCompletionPending; myErr = USBIntRead(&pUniversalPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: Read Interrupt Pipe (ImmediateError)", myErr); } break; default: USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: Transaction initiated with bad refcon value", pUniversalPB->pb.usbRefcon); pUniversalPB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } // At this point the control is returned to the system. If a USB transaction // has been initiated, then it will call the Complete procs // (below) to handle the results of the transaction. } void TransactionCompletionProc (USBPB *pb) { register usbUniversalPBStruct *pUniversalPB; unsigned char * errstring; USBPipeState pipeState; UInt32 i, j, index; UInt32 count, length; USBHIDReportDesc * currentDesc; UInt8 * descriptorStorage; pUniversalPB = (usbUniversalPBStruct *)(pb); pUniversalPB->transDepth--; if (pUniversalPB->transDepth < 0) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: transDepth < 0 (completion)", pUniversalPB->transDepth ); } if (pUniversalPB->transDepth > 1) { USBExpertFatalError(pUniversalPB->interfaceRef, kUSBInternalErr, "\pUSBUniversalModule: transDepth > 1 (completion)", pUniversalPB->transDepth ); } if(pUniversalPB->pb.usbStatus != noErr) // was there an error? { switch(pUniversalPB->pb.usbRefcon & kDriverStagesMask) // yes, so show where the error occurred { case kGetHIDDesc: errstring = "\pUSBUniversalModule: Error during kGetHIDDesc"; break; case kAllocHIDOwnedDescMem: errstring = "\pUSBUniversalModule: Error during kAllocHIDOwnedDescMem"; break; case kGet1OwnedHIDDesc: errstring = "\pUSBUniversalModule: Error during kGet1OwnedHIDDesc"; break; case kConfigureInterface: errstring = "\pUSBUniversalModule: Error during kConfigureInterface"; break; case kFindInterruptPipe: errstring = "\pUSBUniversalModule: Error during kFindInterruptPipe"; break; case kReadInterruptPipe: errstring = "\pUSBUniversalModule: Error during kReadInterruptPipe"; break; default: errstring = "\pUSBUniversalModule: Error occurred, but state is unknown"; break; }; USBExpertFatalError(pUniversalPB->interfaceRef, pUniversalPB->pb.usbStatus, errstring, (pUniversalPB->pb.usbRefcon & kDriverStagesMask)); pUniversalPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); // set up to retry the transaction pUniversalPB->pb.usbRefcon |= kRetryTransaction; pUniversalPB->retryCount--; if ((!pUniversalPB->retryCount) || (pUniversalPB->pb.usbStatus == kUSBAbortedError)) // have we exhausted the retries? { // or received an abort? USBExpertStatus(pUniversalPB->interfaceRef, "\pUSBUniversalModule: Pipe abort or unable to recover from error", pUniversalPB->interfaceRef); pUniversalPB->pb.usbRefcon = kReturnFromDriver; // if so, just exit. } else // if it didn't abort and there's retries left, then... { if (pUniversalPB->pipeRef) // check if the pipe is open. { USBGetPipeStatusByReference(pUniversalPB->pipeRef, &pipeState); // yes, so what it's state? if (pipeState != kUSBActive) // if it's not active, try to clear it. It might be stalled... { USBExpertStatus(pUniversalPB->interfaceRef, "\pUSBUniversalModule: Pipe is open and stalled, clearing stall...", pUniversalPB->interfaceRef); USBClearPipeStallByReference(pUniversalPB->pipeRef); } } } } else { pUniversalPB->pb.usbRefcon &= ~kRetryTransaction; pUniversalPB->retryCount = kUniversalRetryCount; } if (pUniversalPB->pb.usbRefcon & kCompletionPending) { pUniversalPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); switch(pUniversalPB->pb.usbRefcon) { case kGetHIDDesc: // if we could not get anything, don't try to get the rest if (pUniversalPB->pb.usbActCount == 0) { pUniversalPB->pb.usbRefcon = kConfigureInterface; break; } pUniversalPB->pb.usbRefcon = kAllocHIDOwnedDescMem; break; case kAllocHIDOwnedDescMem: pUniversalPB->hidOwnedDiscriptors = (usbHIDDescriptorInfo *) pUniversalPB->pb.usbBuffer; pUniversalPB->hidOwnedDescriptorsCount = 0; if (pUniversalPB->allocatedBufferSize != pUniversalPB->pb.usbActCount) { USBExpertStatus(pUniversalPB->interfaceRef, "\pUSBUniversalModule: could not allocate descriptor buffer", pUniversalPB->pb.usbActCount); pUniversalPB->pb.usbRefcon = kConfigureInterface; break; } // fill out our 'usbHIDDescriptorInfo' array count = pUniversalPB->hidDiscriptor.d.hidNumDescriptors; currentDesc = (USBHIDReportDesc *) &pUniversalPB->hidDiscriptor.d.hidDescriptorType; descriptorStorage = (UInt8 *) pUniversalPB->hidOwnedDiscriptors; descriptorStorage += count * sizeof (usbHIDDescriptorInfo); // inital part for the array for (i = 0; i < count; i++) { length = (currentDesc->hidDescriptorLengthHi << 8) + currentDesc->hidDescriptorLengthLo; pUniversalPB->hidOwnedDiscriptors[i].type = currentDesc->hidDescriptorType; pUniversalPB->hidOwnedDiscriptors[i].length = length; pUniversalPB->hidOwnedDiscriptors[i].descriptor = descriptorStorage; index = 0; for (j = 0; j < i; j++) if (pUniversalPB->hidOwnedDiscriptors[j].type == currentDesc->hidDescriptorType) index++; pUniversalPB->hidOwnedDiscriptors[i].typeIndex = index; currentDesc = (USBHIDReportDesc *) (((UInt8 *) currentDesc) + 3); // make _sure_ we add 3 bytes not 4 regardless of struct alignment descriptorStorage += length; } // next, we'll get the 1st owned descriptor (by 1.0 spec there will _always_ be at least 1) pUniversalPB->pb.usbRefcon = kGet1OwnedHIDDesc; break; case kGet1OwnedHIDDesc: if (pUniversalPB->hidOwnedDiscriptors[pUniversalPB->hidOwnedDescriptorsCount].length != pUniversalPB->pb.usbActCount) USBExpertStatus(pUniversalPB->interfaceRef, "\pUSBUniversalModule: get owned HID descriptor wrong size", pUniversalPB->pb.usbActCount); // we successfully got it, so increment pUniversalPB->hidOwnedDescriptorsCount++; // now get more if we need to, otherwise move on if (pUniversalPB->hidOwnedDescriptorsCount < pUniversalPB->hidDiscriptor.d.hidNumDescriptors) pUniversalPB->pb.usbRefcon = kGet1OwnedHIDDesc; else // we're done pUniversalPB->pb.usbRefcon = kConfigureInterface; break; case kConfigureInterface: pUniversalPB->numPipes = pUniversalPB->pb.usbOther; pUniversalPB->pb.usbRefcon = kFindInterruptPipe; break; case kFindInterruptPipe: pUniversalPB->pipeRef = pUniversalPB->pb.usbReference; pUniversalPB->maxPacketSize = pUniversalPB->pb.usbWValue; pUniversalPB->pb.usbRefcon = kReadInterruptPipe; break; case kReadInterruptPipe: NotifyRegisteredHIDUser(pUniversalPB->hidReport); pUniversalPB->pb.usbRefcon = kReadInterruptPipe; break; } } if (!(pUniversalPB->pb.usbRefcon & kReturnFromDriver)) UniversalModuleInitiateTransaction(pb); } void DriverEntry(USBDeviceRef device, USBDeviceDescriptorPtr pDeviceDescriptor) { #pragma unused (device) #pragma unused (pDeviceDescriptor) static Boolean beenThereDoneThat = false; return; } void InterfaceEntry(UInt32 interfaceNum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBInterfaceRef interfaceRef) { static Boolean beenThereDoneThat = false; if(beenThereDoneThat) { USBExpertFatalError(interfaceRef, kUSBInternalErr, "\pUSBUniversalModule is not reentrant", 0); return; } beenThereDoneThat = true; // store off parameters myUniversalPB.interfaceNum = interfaceNum; myUniversalPB.interfaceDescriptor = *pInterfaceDescriptor; myUniversalPB.deviceDescriptor = *pDeviceDescriptor; myUniversalPB.interfaceRef = interfaceRef; myUniversalPB.transDepth = 0; myUniversalPB.retryCount = kUniversalRetryCount; myUniversalPB.pClientInterruptRoutine = nil; myUniversalPB.clientRefCon = 0; myUniversalPB.pipeRef = nil; SetParamBlock(interfaceRef, &myUniversalPB.pb); USBExpertStatus(myUniversalPB.interfaceRef, "\pUSBUniversalModule: Driver loaded and starting up...", myUniversalPB.interfaceRef); myUniversalPB.pb.usbRefcon = kGetHIDDesc; UniversalModuleInitiateTransaction(&myUniversalPB.pb); } void InterfaceExit(USBInterfaceRef interfaceRef, USBInterfaceDescriptorPtr pInterfaceDescriptor) { #pragma unused (pInterfaceDescriptor) OSStatus myErr; USBExpertStatus(interfaceRef, "\pUSBHIDUniversalModule: Finalize", interfaceRef); if (myUniversalPB.pipeRef != 0) { USBExpertStatus(interfaceRef, "\pUSBHIDMouseModule: Aborting interrupt pipe", interfaceRef); USBAbortPipeByReference(myUniversalPB.pipeRef); myUniversalPB.pipeRef = 0; } if (myUniversalPB.hidOwnedDiscriptors != nil) { myUniversalPB.pb.usbReference = interfaceRef; myUniversalPB.pb.pbVersion = kUSBCurrentPBVersion; myUniversalPB.pb.usbFlags = 0; myUniversalPB.pb.usbRefcon = 0; myUniversalPB.pb.usbBuffer = myUniversalPB.hidOwnedDiscriptors; myUniversalPB.pb.usbCompletion = kUSBNoCallBack; myErr = USBDeallocMem(&myUniversalPB.pb); myUniversalPB.hidOwnedDiscriptors = nil; } }